#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "client.h"

#include <stdio.h>
static ssize_t tcp_buffer_forward(tcp_client *client)
{
	ssize_t size;
	while((size = read(client->sock, client->buffer.head, TCP_CLIENT_BUFFER_SIZE)) == -1)
	{
		if(errno == EINTR) continue;
		client->buffer.status = TCP_CLIENT_BUFSTAT_FAILED; 
		return -1;
	}
	if(size == 0)
		client->buffer.status = TCP_CLIENT_BUFSTAT_END;

	client->buffer.head[size] = '\0';
	client->buffer.status = TCP_CLIENT_BUFSTAT_READY;
	client->buffer.used = 0;
	client->buffer.size = size;
	client->buffer.cur  = client->buffer.head;
	return size;
}


char tcp_readchar(tcp_client *client)
{
	if(  client->buffer.status == TCP_CLIENT_BUFSTAT_UNSET
	  || client->buffer.used   == client->buffer.size )
	{
		/* some error occur. */
		if(tcp_buffer_forward(client) == -1)
			return '\0';

		/* at the end of read. */
		if(client->buffer.size == 0)
			return '\0';
	}

	client->buffer.used++;
	return *client->buffer.cur++;
}

size_t tcp_readline(tcp_client *client, char *dest, size_t maxlen)
{
	char c;
	size_t i;
	for(i = 0; i < maxlen; i++)
	{
		c = tcp_readchar(client);
		if(c == '\0' || c == LF)
		{
			if(i != 0 && dest[i-1] == CR)
				dest[i-1] = '\0';
			break;
		}
		
		dest[i] = c;
	}
	
	dest[i] = '\0';
	return i;
}

ssize_t tcp_read(tcp_client *client, void* dest, size_t length)
{
	char *tail;
	size_t left, size;

	tail = (char*)dest;
	left = length;
start_read:
	if(  client->buffer.status == TCP_CLIENT_BUFSTAT_UNSET
	  || client->buffer.used   == client->buffer.size )
	{
		if(tcp_buffer_forward(client) == -1)
			return -1;
	}
	if(client->buffer.size == 0)
		/* at end of the buffer. */
		return length - left;

	size = client->buffer.size - client->buffer.used;
	if(size > left)
		size = left;
	memcpy(tail, client->buffer.cur, size);
	client->buffer.used += size;
	left -= size;
	tail += size;
	if(left == 0)
	{
		*tail = '\0';
		return length;
	}	
	goto start_read;
}

ssize_t tcp_write(tcp_client *client, const void *data, size_t length)
{
	char *tail;
	size_t left;
	ssize_t size;

	tail = (char*)data;
	left = length;

start_write:
	if((size = write(client->sock, tail, left)) == -1)
	{
		if(errno == EINTR)
			goto start_write;

		return -1;
	}

	left -= size;
	tail += size;
	if(left == 0)
		return length;

	goto start_write;
}

